package springintegrationsample.test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory;
import org.springframework.integration.ip.util.TestingUtilities;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import springintegrationsample.CustomTestContextLoader;
import springintegrationsample.runner.FixPackageDeserializer;
import springintegrationsample.runner.codec.SendByteToFix;

import com.hundsun.fasp.trans.fix.base.FixData;

/**
 * 包含了加解密的客户端服务端，加解密逻辑直接写在了正反序列化逻辑之中
 * @author chenjiao
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=CustomTestContextLoader.class,
	locations = {"/tcpServerUserDemo-fix2.xml"})
@DirtiesContext
public class TcpFixServerTestCodec2 {

	private static final Logger LOGGER = Logger.getLogger(TcpFixServerTestCodec2.class);

	@Autowired
	@Qualifier("incomingServerChannel")
	MessageChannel incomingServerChannel;

	@Value("${availableServerSocket}")
	int availableServerSocket;

	@Autowired
	AbstractServerConnectionFactory serverConnectionFactory;

	@Before
	public void setup() {
		TestingUtilities.waitListening(this.serverConnectionFactory, 10000L);
	}

	@Test
	public void testHappyPath() {
		// add a listener to this channel, otherwise there is not one defined
		// the reason we use a listener here is so we can assert truths on the
		// message and/or payload
		SubscribableChannel channel = (SubscribableChannel) incomingServerChannel;
		channel.subscribe(new AbstractReplyProducingMessageHandler(){

			@Override
			protected Object handleRequestMessage(Message<?> requestMessage) {
				FixData payload = (FixData) requestMessage.getPayload();
				System.out.println("========================");
				System.out.println("payload.getColumnCount()");
				System.out.println(payload.getColumnCount());
				System.out.println("========================");
				assertEquals(5, payload.getColumnCount());
				return requestMessage;
			}
		});

		FixData data = getFixData();
		byte[] bytes = null;
		try {
			bytes = SendByteToFix.make(data);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		// use the java socket API to make the connection to the server
		Socket socket = null;
		OutputStream out = null;
		InputStreamReader in = null;

		try {
			socket = new Socket("localhost", availableServerSocket);
			out = socket.getOutputStream();
			out.write(bytes);
			out.flush();
			FixData payload =FixPackageDeserializer.parse(socket.getInputStream());
			assertEquals(5, payload.getColumnCount());

		} catch (IOException e) {
			e.printStackTrace();
			LOGGER.error(e.getMessage(), e);
			fail(String.format("Test (port: %s) ended with an exception: %s", availableServerSocket, e.getMessage()));
		} finally {
			try {
				socket.close();
				out.close();
				in.close();

			} catch (Exception e) {
				// swallow exception
			}

		}
	}
	
	public FixData getFixData(){
		FixData fd = new FixData();
		fd.addColumn("a", "String", true);
		fd.addColumn("b", "String", true);
		fd.addColumn("c", "String", true);
		fd.addColumn("d", "String", true);
		fd.addColumn("e", "String", true);
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("a", "1");
		map.put("b", "1");
		map.put("c", "1");
		map.put("d", "1");
		map.put("e", "1");
		fd.addValue(map);
		return fd;
	}

}
